#include "decodevideothread.h"
#include <QDebug>

#define SHOWTYPE 0   //0为使用QWidget显示，1为使用OpenGL显示

DecodeVideoThread::DecodeVideoThread()
{
    mFmtCtx = avformat_alloc_context();
    mPkt = av_packet_alloc();
    mYUVFrame = av_frame_alloc();
    mRGBFrame = av_frame_alloc();
}

DecodeVideoThread::~DecodeVideoThread()
{
    if(!mPkt)
        av_packet_free(&mPkt);
    if(mOutBuffer)
        av_free(mOutBuffer);
    if(mYUVFrame)
        av_frame_free(&mYUVFrame);
    if(!mRGBFrame)
        av_frame_free(&mRGBFrame);
    if(!mVideoCodecCtx)
        avcodec_free_context(&mVideoCodecCtx);
    if(!mVideoCodecCtx)
        avcodec_close(mVideoCodecCtx);
    if(!mFmtCtx)
        avformat_close_input(&mFmtCtx);
}

void DecodeVideoThread::stop_run()
{
    mRunStat = false;
}

void DecodeVideoThread::set_url(QString url)
{
    mUrl = url;
}

int DecodeVideoThread::get_width()
{
    return mWidth;
}

int DecodeVideoThread::get_height()
{
    return mHeight;
}

int DecodeVideoThread::open_input_file()
{
    qDebug()<<__FILE__<<__FUNCTION__;
    if(mUrl.isEmpty())
        return -1;

//    if(avformat_open_input(&mFmtCtx,"zhy.flv",NULL,NULL)<0){
    if(avformat_open_input(&mFmtCtx,mUrl.toLocal8Bit().data(),NULL,NULL)<0){
        qDebug()<<"Cannot open input file.";
        return -2;
    }

    if(avformat_find_stream_info(mFmtCtx,NULL)<0){
        qDebug()<<"Cannot find any stream in file.";
        return -3;
    }

    int streamCnt = mFmtCtx->nb_streams;
    for(int i=0; i<streamCnt; i++){
        if(mFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
            mVideoStreamIndex = i;
            continue;
        }
    }

    if(mVideoStreamIndex == -1){
        qDebug()<<"Cannot find video stream in file.";
        return -4;
    }

    AVCodecParameters *videoCodecPara = mFmtCtx->streams[mVideoStreamIndex]->codecpar;

    if(!(mVideoCodec = avcodec_find_decoder(videoCodecPara->codec_id))){
        qDebug()<<"Cannot find valid decode codec.";
        return -5;
    }

    if(!(mVideoCodecCtx = avcodec_alloc_context3(mVideoCodec))){
        qDebug()<<"Cannot find valid decode codec context.";
        return -6;
    }

    if(avcodec_parameters_to_context(mVideoCodecCtx,videoCodecPara)<0){
        qDebug() << "Cannot initialize parameters.";
        return -7;
    }

    if(avcodec_open2(mVideoCodecCtx,mVideoCodec,NULL)<0){
        qDebug()<<"Cannot open codec.";
        return -8;
    }

#if SHOWTYPE
    mWidth = mVideoCodecCtx->width;
    mHeight = mVideoCodecCtx->height;

    mNumBytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P,mWidth,mHeight,1);
    mOutBuffer = (unsigned char *)av_malloc(mNumBytes*sizeof(uchar));
#else
    mImgCtx = sws_getContext(mVideoCodecCtx->width,
                                 mVideoCodecCtx->height,
                                 mVideoCodecCtx->pix_fmt,
                                 mVideoCodecCtx->width,
                                 mVideoCodecCtx->height,
                                 AV_PIX_FMT_RGB32,
                                 SWS_BICUBIC,NULL,NULL,NULL);

    mNumBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB32,mVideoCodecCtx->width,mVideoCodecCtx->height,1);
    mOutBuffer = (unsigned char *)av_malloc(mNumBytes*sizeof(unsigned char));

    int res = av_image_fill_arrays(
                    mRGBFrame->data,mRGBFrame->linesize,
                    mOutBuffer,AV_PIX_FMT_RGB32,
                    mVideoCodecCtx->width,mVideoCodecCtx->height,1);
    if(res<0){
        qDebug()<<"Fill arrays failed.";
        return -9;
    }
#endif

    return 0;
}

void DecodeVideoThread::run()
{
    mRunStat = true;

    if(open_input_file() < 0){
        qDebug()<<"Please input open video file first.";
        return;
    }

    while(mRunStat)
    {
        if(av_read_frame(mFmtCtx,mPkt) >=0 )
        {
            if(mPkt->stream_index == mVideoStreamIndex)
            {
//                qDebug()<<__FILE__<<__FUNCTION__<<" send packet";
                if(avcodec_send_packet(mVideoCodecCtx,mPkt)>=0)
                {
                    int ret;
                    while((ret=avcodec_receive_frame(mVideoCodecCtx,mYUVFrame))>=0){
                        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                            return;
                        else if (ret < 0) {
                            qDebug() << "Error during decoding";
                            exit(1);
                        }
//                        qDebug()<<__FILE__<<__FUNCTION__<<" receive frame";

#if  SHOWTYPE
                        if(mIsFirst){
                            mIsFirst=false;
                            emit sigFirst(mOutBuffer,mWidth,mHeight);
                        }

                        int bytes =0;
                        for(int i=0;i<mHeight;i++){
                            memcpy(mOutBuffer+bytes,mYUVFrame->data[0]+mYUVFrame->linesize[0]*i,mWidth);
                            bytes+=mWidth;
                        }

                        int u=mHeight>>1;
                        for(int i=0;i<u;i++){
                            memcpy(mOutBuffer+bytes,mYUVFrame->data[1]+mYUVFrame->linesize[1]*i,mWidth/2);
                            bytes+=mWidth/2;
                        }

                        for(int i=0;i<u;i++){
                            memcpy(mOutBuffer+bytes,mYUVFrame->data[2]+mYUVFrame->linesize[2]*i,mWidth/2);
                            bytes+=mWidth/2;
                        }

                        emit newFrame();

                        QThread::msleep(24);
#else
                        sws_scale(mImgCtx,
                                  mYUVFrame->data,mYUVFrame->linesize,
                                  0,mVideoCodecCtx->height,
                                  mRGBFrame->data,mRGBFrame->linesize);

                        QImage img(mOutBuffer,
                                   mVideoCodecCtx->width,mVideoCodecCtx->height,
                                   QImage::Format_RGB32);
                        emit sig_send_image(img);
                        QThread::msleep(30);
#endif
                    }
                }
                av_packet_unref(mPkt);
            }
        }else{
            qDebug()<<"All video play done";
        }
    }
    qDebug()<<"Decode video thread stop!";
}


